using System.Configuration;
using System.Globalization;
using Ionic.Zip;
using KML;
//using KML_22_Beta1;
using System;
using System.Collections.Generic;
using System.Web;
//using ICSharpCode.SharpZipLib.Zip;
using System.IO;
using log4net;
using log4net.Config;
using System.Linq;


namespace ODM2KMZ
{
    public partial class ODM2KMZ : System.Web.UI.Page
    {
        private static readonly ILog log = LogManager.GetLogger(typeof(ODM2KMZ));
        private string _currentError = "";

        public string CurrentURL
        {
            get
            {
                if (base.Request.QueryString["URL"] != null)
                {
                    return base.Request.QueryString["URL"];
                }
                return ConfigurationManager.AppSettings["defaultWofService"];
            }
        }

        public string Mode
        {
            get
            {
                if (base.Request.QueryString["Mode"] != null)
                {
                    return base.Request.QueryString["Mode"];
                }
                return "0";
            }
        }

        public string Type
        {
            get
            {
                if (base.Request.QueryString["Type"] != null)
                {
                    return base.Request.QueryString["Type"];
                }
                return "KMZ";
            }
        }

        public string SiteCode
        {
            get
            {
                if (base.Request.QueryString["SiteCode"] != null)
                {
                    return base.Request.QueryString["SiteCode"];
                }
                return string.Empty;
            }
        }

        public string Grouping
        {
            get
            {
                if (base.Request.QueryString["Grouping"] != null)
                {
                    return base.Request.QueryString["Grouping"];
                }
                return "Network";
            }
        }

        public string Show
        {
            get
            {
                if (base.Request.QueryString["Show"] != null)
                {
                    return base.Request.QueryString["Show"];
                }
                return "All";
            }
        }

        public string strPath
        {
            get
            {
                string str;

                str = !base.Request.Url.AbsoluteUri.Contains("?") ? base.Request.Url.AbsoluteUri : base.Request.Url.AbsoluteUri.Remove(base.Request.Url.AbsoluteUri.IndexOf("?"));
                return string.Concat(str.Replace(base.Request.Url.AbsolutePath, ""), base.Request.ApplicationPath);
            }
        }
        public string strPathFake
        {
            get
            {
                return Request.Url.GetLeftPart(System.UriPartial.Authority) +
                             "/" + HttpContext.Current.Request.ApplicationPath + "/";
             
            }
        }

        public string strCurrentError
        {
            get
            {
                return _currentError;

            }
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            if (CurrentURL.Equals(String.Empty))
            {
                base.Response.Redirect("ODM2KMZGateway.aspx");
            }
        }


        protected void Page_PreRender(object sender, EventArgs e)
        {
            base.Response.Clear();
            if (Type.Equals("KML"))
            {
                base.Response.AppendHeader("Content-Disposition", "inline;filename=ODMData.kml");
                base.Response.ContentType = "application/vnd.google-earth.kml+xml kml";
            }
            else
            {
                base.Response.AppendHeader("Content-Disposition", "inline;filename=ODMData.kmz");
                base.Response.ContentType = "application/vnd.google-earth.kmz kmz";
            }

            if (Mode.Equals("0"))
            {
                base.Response.BinaryWrite(GetNetworkLinkKMZ());
            }
            if (Mode.Equals("1"))
            {
                base.Response.BinaryWrite(GetDataKMZ());
            }
            base.Response.End();
        }


        public byte[] GetKMZ(string DocumentName,String TheKML)
        {
            //String TheKML = this.GetKML();

            System.Text.UnicodeEncoding encoding = new System.Text.UnicodeEncoding();
            byte[] compressedBuffer = encoding.GetBytes(TheKML);

           
            MemoryStream memoryStream = new MemoryStream();
 
            using (ZipFile zip = new ZipFile())
            {
                zip.AddEntry(DocumentName, compressedBuffer);
                zip.Save(memoryStream);
            }
            //using (ZipOutputStream ZipStream = new ZipOutputStream(memoryStream))
            //{
            //    //ZipEntry Entry = new ZipEntry(DocumentName);
            //    //Entry.Size = compressedBuffer.Length;
            //    //ZipStream.SetLevel(9);
            //    //ZipStream.UseZip64 = UseZip64.Off;
            //    //ZipStream.PutNextEntry(Entry);
            //    //ZipStream.Write(compressedBuffer, 0, compressedBuffer.Length);
            //    //ZipStream.CloseEntry();
            //    //ZipStream.Close();

            //}
            return memoryStream.ToArray();
        }

        protected void Page_Unload(object sender, EventArgs e)
        {
        }

        //Get the network links for the variable balloons
        private byte[] GetDataKMZ()
        {
        
            WaterOneFlow waterOneFlow = initWaterOneFlow();
            
           // KMLXML kMLXML = new KMLXML();
             var kMLXML = new KMLDocument();
            Document document = new Document(SiteCode, "HIS Datastream");
            //kMLXML.Documents.Add(document);
            kMLXML.Feature=document;

            //Declare the balloon description and style
            SiteInfoResponseTypeSite siteInfoResponseTypeSite;
            string dataseriesDescription = string.Empty;
            Style style = GetStyle("WRON_Data","/Images/graph-128x128.png", true);

            //Build the baloon description and style
            System.Drawing.Color  errorColour = System.Drawing.Color.HotPink;
            try
            {

                
                //Create the data description for when dataseries exist for a site
                siteInfoResponseTypeSite = waterOneFlow.GetSiteInfoObject(SiteCode, String.Empty).site[0];

                seriesCatalogTypeSeries[] SeriesCatalogTypeSeriess = siteInfoResponseTypeSite.seriesCatalog[0].series;
                dataseriesDescription += CreateHeading(string.Format("{0} Dataset(s)<br><br>", SeriesCatalogTypeSeriess.Length));
                for (int i = 0; i < (int)SeriesCatalogTypeSeriess.Length; i++)
                {
                    seriesCatalogTypeSeries SeriesCatalogTypeSeries = SeriesCatalogTypeSeriess[i];
                    dataseriesDescription += string.Format(
                        "<table><tr>" +
                        "<td width=25 align=center>" +
                        "<a href='{6}WaterOneFlowTableStreamer.aspx?URL={7}&SiteCode={8}&VariableCode={19}:{9}&BeginDate={4}&EndDate={5}'><img src='{16}/Images/Download.jpg' width='25' height='25' alt = 'Get Data'></a><br><font color='#008000'>{3}</font>" +
                        "</td>" +
                        "<td>" +
                        "<b><font size='+2' color='#14B2FF'>{0}</font></b>" +
                        "<br>" +
                        "<b><i><font size='+1' color='#14B2FF'>{10}</font></i></b>" +
                        "<ul>" +
                        "<li><b>General Catagory:</b> {1}" +
                        "<li><b>Sample Medium:</b> {12}" +
                        "<li><b>Data Type:</b> {13}" +
                        "<li><b>Units:</b> {2} ({11})" +
                        "<li><b>Quality Control Level:</b> {14}" +
                        "<li><b>Organisation:</b> {15}" +
                        "<li><b>Begin Date:</b> {4}" +
                        "<li><b>End Date:</b> {5}" +
                        "<br>" +
                        "<a href='{16}/MetadataDataset.aspx?URL={7}&SiteCode={8}&VariableCode={9}&MethodID={17}&QualityControlLevelID={14}&SourceID={18}'>more...</a>" +
                        "<br>" +
                        "<br>" +
                        "</ul>" +
                        "</td>" +
                        "</tr></table>",

                        new object[] {
                        SeriesCatalogTypeSeries.variable.variableName, 
                        SeriesCatalogTypeSeries.variable.generalCategory, 
                        SeriesCatalogTypeSeries.variable.units.Value, 
                        SeriesCatalogTypeSeries.valueCount.Value, 
                        ((TimeIntervalType)SeriesCatalogTypeSeries.variableTimeInterval).beginDateTime.ToString("yyyy-MM-ddTHH:mm:ss"), 
                        ((TimeIntervalType)SeriesCatalogTypeSeries.variableTimeInterval).endDateTime.ToString("yyyy-MM-ddTHH:mm:ss"), 
                        strPathFake, CurrentURL, SiteCode, 
                        SeriesCatalogTypeSeries.variable.variableCode[0].Value,
                        SeriesCatalogTypeSeries.Method.MethodDescription,SeriesCatalogTypeSeries.variable.units.unitsAbbreviation,
                        SeriesCatalogTypeSeries.variable.sampleMedium,
                        SeriesCatalogTypeSeries.variable.dataType,
                        SeriesCatalogTypeSeries.QualityControlLevel.QualityControlLevelID,
                        SeriesCatalogTypeSeries.Source.Organization,
                        strPath,SeriesCatalogTypeSeries.Method.methodID.ToString(),
                        SeriesCatalogTypeSeries.Source.sourceID.ToString(),
                        siteInfoResponseTypeSite.siteInfo.siteCode[0].network});

                }

            }
            catch
            {
                //Create the data description for when no dataseries exist for a site
                string[] sitearray = new string[] { SiteCode };

                siteInfoResponseTypeSite = waterOneFlow.GetSites(sitearray,string.Empty).site[0];
                style.IconStyle.Color = errorColour;
                dataseriesDescription = string.Format("<br><br>" +
                                        "<table><tr>" +
                                        "<td align=center>" +
                                        "<img src='{0}/Images/ErrorCircle-128x128.png' width='20' height='20'>" +
                                        "</td>" +
                                        "<td>" +
                                        "<b><font color='#CC3300' size='+2'>    No Data Available</font></b>" +
                                        "</td>" +
                                        "</tr></table>", strPath);

            }

            //Create the placemark
            if (!(Show.Equals("Data") && style.IconStyle.Color == errorColour))
            {
                double latitude = ((LatLonPointType)siteInfoResponseTypeSite.siteInfo.geoLocation.geogLocation).latitude;
                double longitude = ((LatLonPointType)siteInfoResponseTypeSite.siteInfo.geoLocation.geogLocation).longitude;
               // Placemark placemark = new Placemark(siteInfoResponseTypeSite.siteInfo.siteName.Replace("&", "&amp"), CreateCDATA(dataseriesDescription), latitude, longitude, 0.0);
                Placemark placemark = new Placemark();
                placemark.Id = siteInfoResponseTypeSite.siteInfo.siteName.Replace("&", "&amp");
                placemark.Description = CreateCDATA(dataseriesDescription);
                Coordinate coordinate = new Coordinate( latitude,  longitude, 0.0);
                Point location = new Point(coordinate);
                placemark.Geometry = location;
              
                placemark.Snippet = new Snippet(SiteCode);
                placemark.StyleUrl = "#WRON_Data";

                placemark.Region = new Region();
              
                LatLonAltBox llb = new LatLonAltBox();
                llb.North = latitude + 0.1;
                llb.South = latitude - 0.1;
                llb.East = longitude + 0.1;
                llb.West = longitude - 0.1;
                placemark.Region.LatLonAltBox = llb;
                LevelOfDetail lod = new LevelOfDetail();
                lod.MinLodPixels = 128;
                placemark.Region.Lod = lod;
         
                
                //Add the style and placem ark to the document
               // document.StyleSelector.Style;
                document.Styles.Add(style);

                //document.Placemarks.Add(placemark);
                document.Features.Add(placemark);
         
            }
            //Create a network link control for the data KML document
            NetworkLinkControl networkLinkControl = new NetworkLinkControl();
            networkLinkControl.Expires = DateTime.Now.AddDays(7.0).ToString("O");
            networkLinkControl.MinRefreshPeriod = 3600;
          //  kMLXML.KmlObjects.Add(networkLinkControl);
            kMLXML.NetworkLinkControl =networkLinkControl;
            if (Type.Equals("KML"))
            {
                System.Text.Encoding enc = System.Text.Encoding.ASCII;
                byte[] myByteArray = enc.GetBytes(kMLXML.WriteToString());
                return myByteArray;
            }
            else
            {
                return GetKMZ("SiteDataODM.kml", kMLXML.WriteToString());
            }
        }



        private bool HasRecentData(SiteInfoResponseTypeSite site, DateTime recentDate)
        {
            if (site.seriesCatalog == null)
            {
                WaterOneFlow waterOneFlow = initWaterOneFlow();
                site = waterOneFlow.GetSiteInfoObject(string.Format("{0}:{1}", site.siteInfo.siteCode[0].network, site.siteInfo.siteCode[0].Value), string.Empty).site[0];
            }
            seriesCatalogTypeSeries[] SeriesCatalogTypeSeriess = site.seriesCatalog[0].series;
            for (int i = 0; i < (int)SeriesCatalogTypeSeriess.Length; i++)
            {
                TimeIntervalType timeIntervalType = ((TimeIntervalType)SeriesCatalogTypeSeriess[i].variableTimeInterval);
                if (timeIntervalType.endDateTime >= recentDate)
                {
                    return true;
                }
            }
            return false;
        }


        //Get the network links for the site balloons
        private Byte[] GetNetworkLinkKMZ()
        {
            SiteInfoResponseType siteInfoResponseType = null;

            WaterOneFlow waterOneFlow = initWaterOneFlow();
            var sitearray = new string[] { string.Empty };

            try
            {
               siteInfoResponseType = waterOneFlow.GetSites(sitearray, string.Empty);
                //String xml = waterOneFlow.GetSitesXml(sitearray, string.Empty);

            }
            catch(Exception e)
            {
             log.Debug("Exception Caught line 375 ODM2KMZ.aspx.cs " + e.Message);
             throw new Exception("Unable to get sites data from " + CurrentURL + "<BR/>" +
                    e.Message);
            }


            //************************
            //       Root Node
            //************************

            //Create the KML Document
            //KMLXML kMLXML = new KMLXML();
            var kMLXML = new KMLDocument();
            Document document = new Document("Hydrologic Information System");
            //document.Snippet.Text = "WaterOneFlow Services";
            document.Id = string.Format("{0}_{1}",document.Name,document.Snippet);
            document.Styles.Add(GetStyle("WRON_Site", "/Images/browser-128x128.png", false,true ));
            document.Styles.Add(GetStyle("WRON_Folder", "/Images/Network-Folder-smooth-128x128.png", false));//Images/Blue-Sites-128x128.png
            document.Styles.Add(GetStyle("WRON_Root", "/Images/dot-Mac-Logo-128x128.png", false));
            document.Snippet = new Snippet("WaterOneFlow Services"); ;
            document.Description = CreateCDATA(string.Format("<div align='center'><table><tr><td align='center'><img src='{0}/Images/cuahsi_logo.jpg' alt='CUAHSI'><br><br>http://www.cuahsi.org<br><br><br><img src='{0}/Images/logo-csiro70.gif' alt='Commonwealth Scientific and Industrial Research Organisation'><br><br>http://www.csiro.au<br></td></tr></table></div>", strPath));
            document.StyleUrl = "#WRON_Root";

            kMLXML.Feature=document;


            //************************
            //         Folders
            //************************
            
            
            //Manage the folders in the KML document
            Dictionary<String, Folder> folderDictionary = new Dictionary<string, Folder>();
            Folder folder;
            string key = string.Empty;
            SiteInfoResponseTypeSite[] siteInfoResponseTypeSites = siteInfoResponseType.site;
            for (int i = 0; i < (int)siteInfoResponseTypeSites.Length; i++)
            {

                //if (HasRecentData(siteInfoResponseTypeSites[i], DateTime.Today.AddMonths(-6)))
                {
                    SiteInfoType siteInfoType = siteInfoResponseTypeSites[i].siteInfo;
                    SiteInfoTypeSiteCode siteInfoTypeSiteCode = siteInfoType.siteCode[0];
                    LatLonPointType latLongPointType = (LatLonPointType)siteInfoType.geoLocation.geogLocation;

                    try
                    {
                        switch (Grouping)
                        {
                            case "Network":
                                key = string.Concat(Grouping, ":", siteInfoTypeSiteCode.network);
                                break;
                            case "County":
                                key = getNote(siteInfoType, Grouping);
                                break;
                            case "State":
                                key = getNote(siteInfoType, Grouping);
                                break;
                            case "Site Comments":
                                key = getNote(siteInfoType, Grouping);
                                break;
                            case "Elevation":
                                key = siteInfoType.elevation_m.ToString();
                                break;
                            case "SiteCode":
                                key = siteInfoType.siteCode[0].Value;
                                break;
                            case "VerticalDatum":
                                key = siteInfoType.verticalDatum;
                                break;
                            case "SRS":
                                key = siteInfoType.geoLocation.geogLocation.srs;
                                break;
                            case "Projection":
                                key = siteInfoType.geoLocation.localSiteXY[0].projectionInformation;
                                break;
                        }
                    }
                    catch
                    {
                        key = string.Concat("Unknown ", Grouping);
                    }
                    finally
                    {
                        //Retrieve the folder from the dictionary
                        folderDictionary.TryGetValue(key, out folder);

                        //Create the folder if it does not alreay exist
                        if (folder == null)
                        {
                            folder = new Folder(key);
                            folder.StyleUrl = "WRON_Folder";
                            folderDictionary.Add(folder.Name, folder);
                            document.Features.Add(folder);
                        }
                    }



                    //************************
                    //   Site Network Link
                    //************************

                    //Build the URL to get the data network link
                    string sitecode = string.Concat(siteInfoTypeSiteCode.network, ":", siteInfoTypeSiteCode.Value);
                    string siteurl = string.Format("{0}ODM2KMZ.aspx?Mode=1&SiteCode={1}&URL={2}&Show={3}&Type={4}", strPath, sitecode, CurrentURL, Show, Type);


                    //Create a network link
                  //  NetworkLink networkLink = new NetworkLink(siteInfoType.siteName.Replace("&","&#38;"));
                    NetworkLink networkLink = new NetworkLink();
           networkLink.Id  = siteInfoType.siteName.Replace("&", "&#38;");
                    networkLink.Snippet = new Snippet(sitecode); ;
                    networkLink.StyleUrl = "#WRON_Site";
                    networkLink.Link = new Link();
                    networkLink.Link.Href = siteurl.Replace("&", "&amp;");
                    networkLink.Link.RefreshMode = RefreshModeEnum.OnInterval;


                    //Build the description for the network link
                    string descriptionLine;
                    string newLine = "<br>";

                    String description = "<br>";
                    description += CreateHeading("Spatial Reference System");
                    description += string.Format("<b>Latitude: </b>{0}{1}", latLongPointType.latitude, newLine);
                    description += string.Format("<b>Longitude: </b>{0}{1}", latLongPointType.longitude, newLine);
                    description += string.Format("<b>Spatial Reference: </b>{0}{1}{1}", latLongPointType.srs, newLine);

                    try
                    {
                        description += string.Format("<b>Elevation (m): </b>{0}{1}", siteInfoType.elevation_m, newLine);
                        description += string.Format("<b>Vertical Datum: </b>{0}{1}{1}", siteInfoType.verticalDatum, newLine);
                    }
                    catch { }

                    if (siteInfoType.geoLocation.localSiteXY != null)
                    {
                        SiteInfoTypeGeoLocationLocalSiteXY siteInfoTypeGeoLocation = siteInfoType.geoLocation.localSiteXY[0];
                        description += CreateHeading("Local Projection");
                        description += string.Format("<b>X Local Projection: </b>{0}{1}", siteInfoTypeGeoLocation.X, newLine);
                        description += string.Format("<b>Y Local Projection: </b>{0}{1}", siteInfoTypeGeoLocation.Y, newLine);
                        description += string.Format("<b>Projection: </b>{0}{1}{1}", siteInfoTypeGeoLocation.projectionInformation, newLine);
                    }

                    if (siteInfoType.note != null)
                    {
                        description += CreateHeading("Notes");
                        for (int j = 0; j < siteInfoType.note.Length; j++)
                        {
                            descriptionLine = string.Format("<b>{0}: </b>{1}", siteInfoType.note[j].title, siteInfoType.note[j].Value);    //build current line
                            descriptionLine = string.Concat(descriptionLine, newLine);                                       //append new line tag
                            description += descriptionLine;                                                                 //add line to description
                        }

                    }
                    networkLink.Description = CreateCDATA(description);

                    folder.Features.Add(networkLink);
                }
            }



            //************************
            //    Modify Folders
            //************************
           //foreach (Folder f in document.Folders)
            foreach (var it in document.Items)
            {
                if (it.GetType() == typeof (Folder))
                {
                    var f = (Folder) it;
                    IEnumerable<NetworkLink> links = f.Items.Where(x => x.GetType() == typeof(NetworkLink)).Select(i =>(NetworkLink)i);
                    //f.Snippet = string.Format("{0} Observation(s)", f.NetworkLinks.Count);
                    f.Snippet =  new Snippet(string.Format("{0} Observation(s)", links.Count()));
                    f.Description = "<br>";
                    f.Description += CreateHeading("Site Listing");
                    f.Description += "<ul>";

                  //  foreach (NetworkLink nl in f.NetworkLinks)
                    foreach (NetworkLink nl in links)
                    {
                        f.Description += string.Format("<nobr><li>{0} ({1})<br></nobr>", nl.Name, nl.Snippet);
                    }
                    f.Description += "</ul>";
                    f.Description = CreateCDATA(f.Description);
                }
            }





            //Return the KMZ file
            if (Type.Equals("KML"))
            {
                System.Text.Encoding enc = System.Text.Encoding.ASCII;
                byte[] myByteArray = enc.GetBytes(kMLXML.WriteToString());
                return myByteArray;
            }
            else
            {
                return GetKMZ("NetworkLinkODM.kml", kMLXML.WriteToString());
            }


        }


        private string CreateCDATA(string innerstring)
        {
            return string.Concat("<![CDATA[", innerstring, "]]>");
        }
        private string CreateHeading(string innerstring)
        {
            return string.Format("<font color='#14B2FF' size='+1'><b>{0}</b></font><br>",innerstring );
        }

        private WaterOneFlow initWaterOneFlow()
        {
            
            WaterOneFlow waterOneFlow = new WaterOneFlow();
            waterOneFlow.Url = CurrentURL;
            waterOneFlow.Timeout = 600000;
            waterOneFlow.EnableDecompression = true;
        
            
            
            return waterOneFlow;

        }

        private Style GetStyle(string id, string image, bool addDirections)
        {
            return GetStyle(id, image, addDirections,false);
        }

        private Style GetStyle(string id, string image, bool addDirections, bool addWaterOneFlowService)
        {
            string directions = string.Empty;
            if (addDirections) { directions = "$[geDirections]"; };

            Style style = new Style();
            style.Id = id;
            style.IconStyle = new IconStyle();
 style.IconStyle.Icon = new IconStyleIcon();      
            style.IconStyle.Icon.href = "http://maps.google.com/mapfiles/kml/shapes/water.png";
            //style.IconStyle.Scale = 0.7;
            style.IconStyle.Scale = 1;
            string temp = string.Format("<table><tr><td><img src='{0}{1}' width='40' height='40'></td><td><NOBR><font color='#14B2FF' size='+3'><b>$[name]</b></font><br><font color='#14B2FF' size='+1'><b>$[Snippet]</b></font></NOBR></td><tr></table><hr>$[description]<br>{2}", strPath, image, directions);
            DateTime now = DateTime.Now;
            
            string url=string.Empty;
            if (addWaterOneFlowService)
                url = string.Format("<br><nobr>{0}<nobr>", CurrentURL);

            temp += string.Format("<br><div align='right'><nobr>{0} @ {1}<nobr>{2}</div>", now.ToString("ddd, dd MMM yyyy"), now.ToShortTimeString(),url);

            style.BalloonStyle = new BalloonStyle();
            style.BalloonStyle.text = CreateCDATA(temp);
            return style;

        }
        private string getNote(SiteInfoType siteInfoType, string grouping)
        {
            int i;
            string strGroup = null;

            for (i = 0; i < siteInfoType.note.Length; i++)
            {
                if (siteInfoType.note[i].title == grouping)
                    strGroup =  siteInfoType.note[i].Value;
            }
            if (strGroup == null) strGroup = grouping;

            return strGroup;

        }

        public void Page_Error(object sender, EventArgs e)
        {
            Exception objErr = Server.GetLastError().GetBaseException();
            Session["lastError"] = objErr.Message;
            Response.Redirect("ErrorHandler.aspx");
            Server.ClearError();
        }


    }
}
